/* bytechunk class */
#pragma once

#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>

class Label;

class ByteChunk
{
private:
	std::vector<unsigned char> bytes;
	unsigned int pos;
	unsigned int baseaddress;

	// temporary parallel vector for debug printing
	std::vector<bool> cinfo;

	// Internal references
public:
	struct Reference {
		unsigned int location;
		int offset;	// start byte of reference value
		int length; // length; bytes in (offset, offset+length) of target are put at location
		Label* target;
	};

private:
	std::vector<Reference> refs;

public:
	ByteChunk();

	void SetBaseAddress(unsigned int adr);
	unsigned int GetSize() const;

	// Same thing as GetSize(), actually :I
	unsigned int GetPos() const;

	void AddReference(unsigned int location, Label* target);
	void AddReference(unsigned int location, int offset, int length, Label* target);
	std::vector<Reference> GetReferencesInRange(unsigned int start, unsigned int size) const;
	void ResolveReferences();

	void Byte(unsigned int n);
	void Char(unsigned int n);
	void Short(unsigned int n);
	void Long(unsigned int n);

	// Writes a series of hex bytes to the code chunk from a string.
	// NOTE: string must be a valid sequence of hex digit pairs, optionally separated by spaces.
	// Performs no bounds checking. For internal use only.
	void Code(const std::string &code);

	// Truncates the chunk to the given size
	void Truncate(unsigned int newsize);

	// Some methods for reading data out of a chunk
	unsigned char ReadByte(unsigned int pos) const;
	unsigned short ReadShort(unsigned int pos) const;
	unsigned int ReadLong(unsigned int pos) const;

	// Writes the contents of the chunk to a buffer
	bool WriteChunk(char* buffer, int location, int bufsize) const;


	void PrintCode() const {
		for(unsigned int i = 0; i < bytes.size(); ++i) {
			if(!cinfo[i]) {
				if(i == 0 || cinfo[i-1]) {
					printf("[");
				}
				printf("%02X", bytes[i]);
				if(i == bytes.size()-1 || cinfo[i+1]) {
					printf("]");
				} else printf(" ");
			}
			else
				printf("%c", bytes[i]-0x30);
		}
	}

};

